#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "kapi.h"
#include "diag.h"
#include "wbio.h"

#include "nvtfat.h"
#include "nuc900_reg.h"


#define THREAD_CNT		10
#define TEST_LOOP		5

#define STACK_SIZE		(64*1024)

static cyg_handle_t  	hTest, _hTest1, _hTest2;
static cyg_thread 		ThreadTest, _ThreadTest1, _ThreadTest2;
static UINT8            _Stack[STACK_SIZE], _Stack1[STACK_SIZE], _Stack2[STACK_SIZE];

extern VOID  fsGetErrorDescription(INT nErrCode, CHAR *szDescription, INT bIsPrint);
extern INT   fsBIG5toUnicode(VOID *bstr, VOID *ustr);


/* imported from NVTFAT_DISK.C */
extern PDISK_T		*_fs_ptPDiskList;


static volatile BOOL _bIsCardInserted = FALSE;


static INT  Action_Compare(CHAR *suFileName1, CHAR *szAsciiName1, 
							CHAR *suFileName2, CHAR *szAsciiName2)
{
	INT		hFile1, hFile2;
	INT		nLen1, nLen2, nCount, nStatus1, nStatus2;
	UINT8	buffer1[8192], buffer2[8192];
	
	hFile1 = fsOpenFile(suFileName1, szAsciiName1, O_RDONLY);
	if (hFile1 < 0)
		return hFile1;
	
	hFile2 = fsOpenFile(suFileName2, szAsciiName2, O_RDONLY);
	if (hFile2 < 0)
		return hFile2;
	nCount = 0;
	while (1)
	{
		nStatus1 = fsReadFile(hFile1, buffer1, 8192, &nLen1);
		nStatus2 = fsReadFile(hFile2, buffer2, 8192, &nLen2);
		
		if ((nStatus1 == ERR_FILE_EOF) && (nStatus2 == ERR_FILE_EOF))
		{
			fsCloseFile(hFile1);
			fsCloseFile(hFile2);
			return 0;
		}
		
		if ((nStatus1 < 0) || (nStatus2 < 0))
		{
			diag_printf("Read file error: %x %x\n", nStatus1, nStatus2);
			//cyg_scheduler_lock();
			//while (1);
		}
		
		if (nLen1 != nLen2)
			break;
			
		if (memcmp(buffer1, buffer2, 8192))
			break;
		
		nCount++;
		//if ((nCount % 1024) == 0)
		//	diag_printf("%d KB    \r", nCount);
	}
	
	diag_printf("\nFile Compare failed at offset %x\n", nCount * 1024);
	//cyg_scheduler_lock();
	//while (1);
	
	fsCloseFile(hFile1);
	fsCloseFile(hFile2);
	return -1;
}

static volatile int  task_idx = 0;

void copy_compare_test1(cyg_addrword_t data)
{
	INT     nStatus;
	CHAR	szSrcA[24] = "C:\\1.mp4";
	CHAR	szDstA[24] = "C:\\copya";
	CHAR	suFileName1[64], suFileName2[64];
	INT		i, t0, tmp;

	t0 = cyg_current_time();

	while (1)
	{
		diag_printf("Delete file: %s\n", szDstA);
		fsAsciiToUnicode(szDstA, suFileName1, TRUE);
		nStatus = fsDeleteFile(suFileName1, NULL);
		//if (nStatus < 0)
		//	diag_printf("Failed, status = %x\n", nStatus);
		diag_printf("Delete file %s done.\n", szDstA);

		diag_printf("Copy file: %s\n", szSrcA);
		fsAsciiToUnicode(szSrcA, suFileName1, TRUE);
		fsAsciiToUnicode(szDstA, suFileName2, TRUE);
		
		while (fsCopyFile(suFileName1, NULL, suFileName2, NULL) < 0)
		{
			diag_printf("Disk C Failed, status = %x\n", nStatus);
			cyg_thread_delay(500);
		}

		diag_printf("Copy file %s done.\n", szSrcA);

		diag_printf("Compare file: %s and %s\n", szSrcA, szDstA);
		fsAsciiToUnicode(szSrcA, suFileName1, TRUE);
		fsAsciiToUnicode(szDstA, suFileName2, TRUE);
		
		if (Action_Compare(suFileName1, NULL, suFileName2, NULL) < 0)
		{
			diag_printf("Failed, compare error!!\n");
			//cyg_scheduler_lock();
			//while (1);
		}
		diag_printf("compare file %s done.\n", szSrcA);

		tmp = (cyg_current_time() - t0) / 100;
		diag_printf("%02d:%02d:%02d\n",	tmp / 3600, (tmp % 3600) / 60, tmp % 60);
	}	
}



void copy_compare_test2(cyg_addrword_t data)
{
	INT     nStatus;
	CHAR	szSrcA[24] = "D:\\1.mp4";
	CHAR	szDstA[24] = "D:\\copya";
	CHAR	suFileName1[64], suFileName2[64];
	INT		i, t0, tmp;

	t0 = cyg_current_time();

	while (1)
	{
		diag_printf("Delete file: %s\n", szDstA);
		fsAsciiToUnicode(szDstA, suFileName1, TRUE);
		nStatus = fsDeleteFile(suFileName1, NULL);
		//if (nStatus < 0)
		//	diag_printf("Failed, status = %x\n", nStatus);

		diag_printf("Copy file: %s\n", szSrcA);
		fsAsciiToUnicode(szSrcA, suFileName1, TRUE);
		fsAsciiToUnicode(szDstA, suFileName2, TRUE);
		
		while (fsCopyFile(suFileName1, NULL, suFileName2, NULL) < 0)
		{
			diag_printf("Disk D Failed, status = %x\n", nStatus);
			cyg_thread_delay(500);
		}
		
		tmp = (cyg_current_time() - t0) / 100;
		diag_printf("%02d:%02d:%02d\n",	tmp / 3600, (tmp % 3600) / 60, tmp % 60);

		diag_printf("Compare file: %s and %s\n", szSrcA, szDstA);
		fsAsciiToUnicode(szSrcA, suFileName1, TRUE);
		fsAsciiToUnicode(szDstA, suFileName2, TRUE);
		
		if (Action_Compare(suFileName1, NULL, suFileName2, NULL) < 0)
		{
			diag_printf("Failed, compare error!!\n");
			//exit(0);
		}

		tmp = (cyg_current_time() - t0) / 100;
		diag_printf("%02d:%02d:%02d (%x %x)\n",	tmp / 3600, (tmp % 3600) / 60, tmp % 60, (int)_Stack1, (int)_Stack2);
	}	
}



__align(32) static UINT32 dummy[64*1024];

void test_main(cyg_addrword_t data)
{
	cyg_handle_t 	thread = 0;
	cyg_uint16 		id = 0;
	cyg_thread_info info;
	INT  i;
	UINT32  *ptr;
	
	cyg_thread_create(12, copy_compare_test1, 0, "Test1", 
						_Stack1, STACK_SIZE, &_hTest1, &_ThreadTest1);
	cyg_thread_resume(_hTest1);

	cyg_thread_create(12, copy_compare_test2, 0, "Test2", 
						_Stack2, STACK_SIZE, &_hTest2, &_ThreadTest2);
	cyg_thread_resume(_hTest2);

#if 1
#if 1
	ptr = (UINT32 *)((UINT32)dummy | 0x80000000);
	ptr = dummy;
	while (1)
	{
		for (i = 0; i < 64*1024; i++)
			ptr[i] = i;
		//cyg_thread_yield();
	}
#endif
	while (1)
	{
		while( cyg_thread_get_next( &thread, &id ) )
		{
			if (!cyg_thread_get_info(thread, id, &info))
				break;
			diag_printf("%s - %04x, state: %d\n", info.name, info.id, info.state);
		}
		cyg_thread_delay(500);
	}
#endif	
}



int  main(char *argc[],char *argv[])
{
	WB_PLL_T 		sysClock;

    /* CACHE_ON	*/ 
    sysInvalidCache(); 
    sysEnableCache(CACHE_WRITE_BACK);

	outpw(REG_CLKEN, (inpw(REG_CLKEN)|0x200));  // enable USBH, FMI clock

#if 1
	sysClock.pll0 = PLL_166MHZ;				// PLL0 = 16.934 MHz
	sysClock.pll1 = PLL_66MHZ;				//PLL1 output clock
	sysClock.cpu_src = CPU_FROM_PLL0;		//Select CPU clock source
	sysClock.ahb_clk = AHB_CPUCLK_1_2;		//Select AHB clock divider
	sysClock.apb_clk = APB_AHB_1_2;			//Select APB clock divider
	sysSetPLLConfig(&sysClock);				//Call system function call
#endif

	fsInitFileSystem();

	//outpw(REG_MFSEL, (inpw(REG_MFSEL) & 0xCFFFFFFF) | 0x10000000);
	
	InitUsbSystem();       
	//outpw(0xB00050CC, 0x4);
	UMAS_InitUmasDriver();

 	cyg_thread_create(12, test_main, 0, NULL, _Stack, STACK_SIZE, &hTest, &ThreadTest);
	cyg_thread_resume(hTest);
	return 0;
}


